'use strict';

const _ = require('lodash');

const Utils = require('./utils');
const logger = Utils.logger(__filename);

const Server = require('./controllers/server');
const Client = require('./controllers/client');

const connections = {};

module.exports = (server) => {
  // Client connected
  server.on('clientConnected', (client) => {
    logger.debug('Client Connected:', client.id);
    connections[client.id] = {
      server: {},
      client: {}
    };
  });

  // Client disconnected
  server.on('clientDisconnected', (client) => {
    logger.debug('Client Disconnected:', client.id);
    const connection = connections[client.id];
    _.each(connection.server, (s) => {
      s && s.close();
    });
    _.each(connection.client, (c) => {
      c && c.end();
    });
    connections[client.id] = undefined;
  });

  // Client published
  server.on('published', (packet, client) => {
    packet.payload = packet.payload.toString();
    logger.debug('Client', client && client.id, 'Published', packet);

    if (client) {
      const cmd = Utils.parseJson(packet.topic);
      const payload = Utils.parseJson(packet.payload);
      const connection = connections[client.id];

      try {
        if (cmd.type == 'server' && connection.server[cmd.name]) {
          connection.server[cmd.name][cmd.cmd](payload);
        } else if (cmd.type == 'client' && connection.client[cmd.name]) {
          connection.client[cmd.name][cmd.cmd](payload);
        }
      } catch (err) {
        logger.error(`Command executed error`, err);
      }
    }
  });

  // Client subscribed
  server.on('subscribed', (topic, client) => {
    logger.debug('Client', client.id, 'Topic subscribed', topic);

    const cmd = Utils.parseJson(topic);
    const connection = connections[client.id];

    function publish(payload, callback) {
      server.publish({
        topic,
        payload,
        qos: 2
      }, () => {
        logger.debug('Publish topic', topic, 'payload', payload);
        callback && callback();
      });
    }

    if (cmd.type == 'server') {
      connection.server[cmd.name] = connection.server[cmd.name] || new Server(cmd, publish);
    } else if (cmd.type == 'client') {
      connection.client[cmd.name] = connection.client[cmd.name] || new Client(cmd, publish);
    }
  });

  // Client unsubscribed
  server.on('unsubscribed', (topic, client) => {
    logger.debug('Client', client.id, 'Topic unsubscribed', topic);

    const cmd = Utils.parseJson(topic);
    const connection = connections[client.id];

    if (cmd.type == 'server' && connection.server[cmd.name]) {
      connection.server[cmd.name].close(() => connection.server[cmd.name] = undefined);
    } else if (cmd.type == 'client' && connection.client[cmd.name]) {
      connection.client[cmd.name].end(() => connection.client[cmd.name] = undefined);
    }
  });
};
